/**
 * 版权所有(C)，上海海鼎信息工程股份有限公司，2009，所有权利保留。
 * 
 * 项目名：	rumba-widget2
 * 文件名：	RTitleBox.java
 * 模块说明：	
 * 修改历史：
 * Feb 15, 2009 - lxm - 创建。
 */
package com.hd123.rumba.gwt.widget2.client.panel;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.hd123.rumba.gwt.widget2.client.form.RContainerValidator;
import com.hd123.rumba.gwt.widget2.client.form.RValidatable;
import com.hd123.rumba.gwt.widget2.client.misc.RImageLocation;
import com.hd123.rumba.gwt.widget2.client.toolbar.RToolbar;

/**
 * 提供给任意Panel加上修饰，可能的修饰和部件包括一个显示标题的条，以及可选的位于顶端与底端的工具条。
 * <p>
 * 
 * <b>控件布局结构</b><br>
 * VerticalPanel<br>
 * ..CaptionBar 标题条<br>
 * ..[RToolbar] 顶端工具条<br>
 * ..[Panel]<br>
 * ..[RToolbar] 底端工具条
 * <p>
 * 
 * <b>CSS Style Rules</b> <ol type=disc>
 * <li>.rb-CaptionBox {}</li>
 * <li>.rb-CaptionBox-border {}</li>
 * <li>.rb-CaptionBox .captionBar { 标题条，详情参见{@link RCaptionBar}</li>
 * </ol>
 * 
 * @author lxm
 * 
 */
public class RCaptionBox extends Composite implements HasWidgets, RValidatable {

  public static final String STYLENAME_LEVEL_1 = "rb-CaptionBox-1";
  public static final String STYLENAME_LEVEL_2 = "rb-CaptionBox-2";
  public static final String STYLENAME_LEVEL_3 = "rb-CaptionBox-3";
  public static final String STYLENAME_LEVEL_4 = "rb-CaptionBox-4";
  private static final String STYLENAME_DEFAULT = STYLENAME_LEVEL_2;

  /**
   * 创建对象实例。
   */
  public RCaptionBox() {
    super();
    drawSelf();
    setStyleName(STYLENAME_DEFAULT);
    resHeight = DOM.getStyleAttribute(getElement(), "height");
  }

  private VerticalPanel pnl;
  private RCaptionBar captionBar;
  private RToolbar topToolbar;
  private VerticalPanel contentPanel;
  private Widget content;
  private int contentSpacing = 5;
  private RToolbar bottomToolbar;
  private boolean border = false;

  private boolean minimized = false;
  private boolean maximized = false;
  private String resHeight;
  private boolean resAutoHeightPanel = false;

  /**
   * 取得所包含的标题条控件对象。
   * 
   * @return
   */
  public RCaptionBar getCaptionBar() {
    return captionBar;
  }

  /**
   * 取得标题文本。
   * 
   * @return
   */
  public String getCaption() {
    return captionBar.getCaption();
  }

  /**
   * 设置标题文本。
   * 
   * @param caption
   */
  public void setCaption(String caption) {
    captionBar.setCaption(caption);
  }

  /**
   * 取得标题图标。
   * 
   * @return
   */
  public RImageLocation getIcon() {
    return captionBar.getIcon();
  }

  /**
   * 设置标题图标。
   * 
   * @param icon
   */
  public void setIcon(RImageLocation icon) {
    captionBar.setIcon(icon);
  }

  /**
   * 取得当前所包含的内容面板。
   * 
   * @return
   */
  public Widget getContent() {
    return content;
  }

  /**
   * 设置当前所包含的内容面板。
   * 
   * @param content
   */
  public void setContent(Widget content) {
    if (this.content != null)
      contentPanel.remove(this.content);

    this.content = content;

    if (this.content != null) {
      this.content.setWidth("100%");
      contentPanel.add(this.content);
      contentPanel.setSpacing(contentSpacing);

      // 记录恢复数据，并刷新。
      String height = DOM.getStyleAttribute(pnl.getElement(), "height");
      resAutoHeightPanel = "".equals(height);
      refreshPanel();
    }
  }

  /**
   * 内容面板和最外层边界之间的空隙
   * 
   * @return
   */
  public int getContentSpacing() {
    return contentSpacing;
  }

  /**
   * 内容面板和最外层边界之间的空隙，默认为5像素
   * 
   * @param contentSpacing
   */
  public void setContentSpacing(int contentSpacing) {
    this.contentSpacing = contentSpacing;
    contentPanel.setSpacing(contentSpacing);
  }

  /**
   * 取得当前的顶端工具条。
   * 
   * @return
   */
  public RToolbar getTopToolbar() {
    return topToolbar;
  }

  /**
   * 设置当前顶端工具条。
   * 
   * @param toolbar
   */
  public void setTopToolbar(RToolbar toolbar) {
    if (topToolbar != null)
      pnl.remove(topToolbar);

    topToolbar = toolbar;

    if (topToolbar != null)
      pnl.insert(topToolbar, 1);

    refreshTopToolbar();
  }

  /**
   * 取得当前的底端工具条。
   * 
   * @return
   */
  public RToolbar getBottomToolbar() {
    return bottomToolbar;
  }

  /**
   * 设置当前的底端工具条。
   * 
   * @param toolbar
   */
  public void setBottomToolbar(RToolbar toolbar) {
    if (bottomToolbar != null)
      pnl.remove(bottomToolbar);

    bottomToolbar = toolbar;

    if (bottomToolbar != null)
      pnl.add(bottomToolbar);

    refreshBottomToolbar();
  }

  /**
   * 取得当前是否具有边框。
   * 
   * @return
   */
  public boolean isBorder() {
    return border;
  }

  /**
   * 设置当前是否具有边框。
   * 
   * @param border
   */
  public void setBorder(boolean border) {
    this.border = border;
    if (this.border)
      addStyleDependentName("border");
    else
      removeStyleDependentName("border");
  }

  /**
   * 取得当前是否已经被关闭。
   * 
   * @return
   */
  public boolean isClosed() {
    return isVisible() == false;
  }

  /**
   * 打开使得在界面上可见。
   */
  public void open() {
    setVisible(true);
  }

  /**
   * 关闭时的在界面上不可见。
   */
  public void close() {
    setVisible(false);
  }

  /**
   * 取得当前是否已经最小化。
   * 
   * @return
   */
  public boolean isMinimized() {
    return minimized;
  }

  /**
   * 取得当前是否已经最大化。
   * 
   * @return
   */
  public boolean isMaximized() {
    return maximized;
  }

  /**
   * 最小化显示，即只显示一个标题条。
   */
  public void minimizeSize() {
    minimized = true;
    maximized = false;

    // 记录恢复数据。
    if (content != null) {
      String height = DOM.getStyleAttribute(pnl.getElement(), "height");
      resAutoHeightPanel = "".equals(height);
    }

    refreshTopToolbar();
    refreshBottomToolbar();
    refreshPanel();
    captionBar.minimizeSize();
  }

  /**
   * 最大化显示，即调整高度，使之正好与所属窗口的ClientHeight一致，并滚动至可见。
   */
  public void maximizeSize() {
    minimized = false;
    maximized = true;

    // 记录恢复数据。
    if (content != null) {
      String height = DOM.getStyleAttribute(pnl.getElement(), "height");
      resAutoHeightPanel = "".equals(height);
    }

    refreshTopToolbar();
    refreshBottomToolbar();
    refreshPanel();

    // 设置自身高度。
    if (content != null) {
      super.setHeight(Window.getClientHeight() + "px");
    }

    captionBar.maximizeSize();
    DOM.scrollIntoView(getElement());
  }

  /**
   * 恢复正常显示尺寸。
   */
  public void restoreSize() {
    minimized = false;
    maximized = false;

    refreshTopToolbar();
    refreshBottomToolbar();
    refreshPanel();

    // 设置自身高度。
    if (content != null)
      super.setHeight(resHeight);

    captionBar.doRestoreSize();
    DOM.scrollIntoView(getElement());
  }

  public void setHeight(String height) {
    super.setHeight(height);
    resHeight = height;
  }

  public void add(Widget widget) {
    // 只能添加一个控件
    if (getContent() != null) {
      throw new IllegalStateException("RCaptionBox只能包含一个控件");
    }
    setContent(widget);
  }

  public void clear() {
    setContent(null);
  }

  public Iterator iterator() {
    // Return a simple iterator that enumerates the 0 or 1 elements in this
    // panel.
    return new Iterator() {
      boolean hasElement = content != null;
      Widget returned = null;

      public boolean hasNext() {
        return hasElement;
      }

      public Object next() {
        if (!hasElement || (content == null)) {
          throw new NoSuchElementException();
        }
        hasElement = false;
        return (returned = content);
      }

      public void remove() {
        if (returned != null) {
          RCaptionBox.this.remove(returned);
        }
      }
    };
  }

  public boolean remove(Widget widget) {
    if (content != widget)
      return false;
    setContent(null);
    return true;
  }

  public void clearValidResults() {
    if (content == null)
      return;

    if (content instanceof RValidatable)
      ((RValidatable) content).clearValidResults();
    else if (content instanceof HasWidgets)
      RContainerValidator.clearValidResults((HasWidgets) content);
  }

  public boolean isValid() {
    if (content == null)
      return true;

    if (content instanceof RValidatable)
      return ((RValidatable) content).isValid();
    else if (content instanceof HasWidgets)
      return RContainerValidator.isValid((HasWidgets) content);
    else
      return true;
  }

  public List getInvalidMessages() {
    if (content == null)
      return new ArrayList();

    if (content instanceof RValidatable)
      return ((RValidatable) content).getInvalidMessages();
    else if (content instanceof HasWidgets)
      return RContainerValidator.getInvalidMessages((HasWidgets) content);
    else
      return new ArrayList();
  }

  public boolean validate() {
    if (content == null || !isVisible())
      return true;

    if (content instanceof RValidatable)
      return ((RValidatable) content).validate();
    else if (content instanceof HasWidgets)
      return RContainerValidator.validate((HasWidgets) content);
    else
      return true;
  }

  private void drawSelf() {
    pnl = new VerticalPanel();

    captionBar = new RCaptionBar();
    captionBar.setStyleName("captionBar");
    captionBar.addCaptionBarListener(new Listener_captionBar());
    pnl.add(captionBar);

    contentPanel = new VerticalPanel();
    contentPanel.setWidth("100%");
    pnl.add(contentPanel);

    initWidget(pnl);
  }

  private void refreshTopToolbar() {
    if (topToolbar == null)
      return;
    Element e = DOM.getParent(DOM.getParent(topToolbar.getElement()));
    if (minimized)
      DOM.setStyleAttribute(e, "display", "none");
    else
      DOM.setStyleAttribute(e, "display", "");
  }

  private void refreshBottomToolbar() {
    if (bottomToolbar == null)
      return;
    Element e = DOM.getParent(DOM.getParent(bottomToolbar.getElement()));
    if (minimized)
      DOM.setStyleAttribute(e, "display", "none");
    else
      DOM.setStyleAttribute(e, "display", "");
  }

  private void refreshPanel() {
    if (content == null)
      return;
    Element e = DOM.getParent(DOM.getParent(content.getElement()));
    if (minimized)
      DOM.setStyleAttribute(e, "display", "none");
    else
      DOM.setStyleAttribute(e, "display", "");
    if (maximized)
      DOM.setStyleAttribute(e, "height", "100%");
    else
      DOM.setStyleAttribute(e, "height", "");
    if (resAutoHeightPanel) {
      if (maximized)
        content.setHeight("100%");
      else
        content.setHeight("");
    }
  }

  private class Listener_captionBar implements RCaptionBarListener {

    public void onClose(RCaptionBar sender) {
      close();
    }

    public void onMaximize(RCaptionBar sender) {
      maximizeSize();
    }

    public void onMinimize(RCaptionBar sender) {
      minimizeSize();
    }

    public void onRestore(RCaptionBar sender) {
      restoreSize();
    }

  }
}
